package com.codefish.framework.spring.beans.factory.support;

import com.codefish.framework.spring.beans.factory.IDisposableBean;
import com.codefish.framework.spring.beans.factory.IObjectFactory;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/09/24 下午 06:49
 */
public class DefaultSingletonBeanRegistry implements ISingletonBeanRegistry {


    /**
     * 存储单例bean对象
     */
    protected final Map<String, Object> singletonObjectMap = new ConcurrentHashMap<>(256);
    /**
     * 保存需要在销毁阶段执行销毁钩子方法的单例bean
     */
    protected final Map<String, Object> disposableBeans = new LinkedHashMap<>();


    @Override
    public void registerSingleton(String beanName, Object beanObject) {
        singletonObjectMap.put(beanName, beanObject);
    }

    @Override
    public Object getSingleton(String beanName) {
        return singletonObjectMap.get(beanName);
    }

    /**
     * 获取给定beanName的bean对象，如果没有则获得objectFactory的对象实例并注册到SingletonBeanRegistry中
     *
     * @param beanName      指定beanName
     * @param objectFactory 指定objectFactory
     * @return 符合条件的bean实例
     */
    public Object getSingleton(String beanName, IObjectFactory<?> objectFactory) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance == null) {
            singletonInstance = objectFactory.getObject();
            registerSingleton(beanName, singletonInstance);
        }
        return singletonInstance;
    }

    @Override
    public boolean containsBean(String beanName) {
        return this.singletonObjectMap.containsKey(beanName);
    }

    /**
     * 销毁所有的单例bean
     */
    public void destroySingletons() {
        //destroySingleton()方法涉及到对disposableBeans的remove操作，需要复制一份key列表。
        // 避免出现ConcurrentModificationException异常
        List<String> beanNames = new ArrayList<>(this.disposableBeans.keySet());
        for (String beanName : beanNames) {
            //对于在销毁期间存在钩子方法的bean，执行销毁相关操作
            destroySingleton(beanName);
        }
        //清除其它单例bean缓存
        clearSingletonCache();
    }


    /**
     * 注册一个可销毁的bean
     *
     * @param beanName beanName
     * @param bean     可销毁的bean
     */
    public void registerDisposableBean(String beanName, IDisposableBean bean) {
        this.disposableBeans.put(beanName, bean);
    }

    /**
     * 清除registry中的缓存
     */
    protected void clearSingletonCache() {
        this.singletonObjectMap.clear();
    }

    /**
     * 清除指定的单例bean
     *
     * @param beanName beanName
     */
    public void destroySingleton(String beanName) {
        //从缓存中移除给定beanName的bean实例
        removeSingleton(beanName);
        //尝试将bean转为DisposableBean实例
        IDisposableBean disposableBean;
        disposableBean = (IDisposableBean) this.disposableBeans.remove(beanName);
        //执行DisposableBean的destroy方法
        destroyBean(beanName, disposableBean);
    }

    /**
     * 如果bean不为null，对指定的bean进行销毁操作，触发销毁时的钩子方法
     *
     * @param beanName       目标beanName
     * @param disposableBean 待销毁的bean
     */
    protected void destroyBean(String beanName, IDisposableBean disposableBean) {
        if (disposableBean != null) {
            try {
                disposableBean.destroy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 从缓存中移除某个单例bean
     *
     * @param beanName 目标beanName
     */
    protected void removeSingleton(String beanName) {
        this.singletonObjectMap.remove(beanName);
    }


}
